package apigateway.project.register.Impl;


import apigateway.project.commen.config.ServiceDefinition;
import apigateway.project.commen.config.ServiceInstance;
import apigateway.project.register.Interface.RegisterCenter;
import apigateway.project.register.Interface.RegisterCenterListener;
import apigateway.project.register.listener.NacosServiceListener;
import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingMaintainFactory;
import com.alibaba.nacos.api.naming.NamingMaintainService;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class NacosRegisterCenter implements RegisterCenter {
    /**
     * nacos服务端地址
     */
    private String nacosAddr;

    /**
     * 环境变量
     */
    private String env;
    /**
     * 提供的服务注册和发现的主要接口
     */
    private NamingService namingService;
    /**
     * 提供了维护nacos服务实例的额外操作
     */
    private NamingMaintainService namingMaintainService;

    @Override
    public void init(String registerAddress, String env) {
        this.nacosAddr = registerAddress;
        this.env = env;

        try {
            this.namingService = NamingFactory.createNamingService(nacosAddr);
            this.namingMaintainService = NamingMaintainFactory.createMaintainService(nacosAddr);
        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void register(ServiceDefinition serviceDefinition, ServiceInstance serviceInstance) {
        Instance instance = new Instance();
        instance.setIp(serviceInstance.getIp());
        instance.setPort(serviceInstance.getPort());
        instance.setInstanceId(serviceInstance.getInstanceId());
        instance.setMetadata(Map.of("meta", JSON.toJSONString(serviceInstance)));
        try {
            //服务注册
            namingService.registerInstance(serviceDefinition.getServiceName(),env,instance);
            //更新服务定义
            namingMaintainService.updateService(serviceDefinition.getServiceName(),env,serviceDefinition.getProtectThreshold(),Map.of("meta", JSON.toJSONString(serviceDefinition)));
        } catch (NacosException e) {
            //throw new RuntimeException(e);
            e.printStackTrace();
        }
    }

    /**
     *  服务注销
     * @param serviceDefinition
     * @param serviceInstance
     */
    @Override
    public void deregister(ServiceDefinition serviceDefinition, ServiceInstance serviceInstance) {
        try {
            namingService.deregisterInstance(serviceDefinition.getServiceName(),env,serviceInstance.getIp(),serviceInstance.getPort());
        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 服务订阅
     * @param registerCenterListener
     */
    @Override
    public void subscribe(RegisterCenterListener registerCenterListener) {
        //进行服务订阅
        doSubscribe(registerCenterListener);

        //定时检查是否有新的任务加入
        ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
        service.schedule(()->doSubscribe(registerCenterListener),10, TimeUnit.SECONDS);
    }

    private void doSubscribe(RegisterCenterListener registerCenterListener) {
        try {
            //从nacos中获取已经订阅的服务列表
            Set<String> subscribedServicesName = namingService.getSubscribeServices().stream().map(ServiceInfo::getName).collect(Collectors.toSet());
            int pageNO=1;
            int pageSize=20;
            //分页从nacos中获取服务列表
            List<String> services = namingService.getServicesOfServer(pageNO, pageSize, env).getData();
            while(services != null && !services.isEmpty()) {
                services.forEach(x -> {
                    if (!subscribedServicesName.contains(x)) {
                        //没有订阅,执行更新操作
                        EventListener eventListener = new NacosServiceListener(namingMaintainService, namingService, env,registerCenterListener);
                        eventListener.onEvent(new NamingEvent(x,null));
                        //订阅该服务
                        try {
                            //为该服务注册一个事件监听器,监听服务的变化
                            namingService.subscribe(x, env, eventListener);
                        } catch (NacosException e) {
                            throw new RuntimeException(e);
                        }
                    }

                });
                services =namingService.getServicesOfServer(++pageNO,pageSize,env).getData();
            }
        } catch (NacosException e) {
            throw new RuntimeException(e);
        }
    }


}
